package com.util_code.widget.recycleadpter;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.paging.PagedListAdapter;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

public abstract class BasePageRcvAdapter<T, VH extends ViewHolder> extends PagedListAdapter<T, VH> {

    public static final int LOADING_VIEW_TYPE = 0x00001000;

    protected Context mContext;
    private Handler mMainHandler;

    protected NetworkState mNetworkState;
    private PageLoadMoreView mPageLoadMoreView = new PageLoadMoreView();
    private int mLoadMorePos;

    RetryCallback mRetryCallback;

    public BasePageRcvAdapter(Context context, DiffUtil.ItemCallback<T> itemCallback, RetryCallback retryCallback) {
        super(itemCallback);
        mRetryCallback = retryCallback;
        mContext = context;
        mMainHandler = new Handler(Looper.getMainLooper());
    }

    private boolean hasExtraRow() {
        return mNetworkState != null && mNetworkState != NetworkState.LOADED;
    }

    public void setNetworkState(NetworkState newNetworkState) {
        if (getCurrentList() != null) {
            if (getCurrentList().size() != 0) {
                if (newNetworkState.getStatus() == NetworkState.Status.RUNNING) {
                    mLoadMorePos = getItemCount() - 1;
                } else {
                    mLoadMorePos = mLoadMorePos + 1;
                }
                NetworkState previousState = mNetworkState;
                boolean hadExtraRow = hasExtraRow();
                mNetworkState = newNetworkState;
                boolean hasExtraRow = hasExtraRow();
                if (hadExtraRow != hasExtraRow) {
                    if (hadExtraRow) {
                        mMainHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                notifyItemRemoved(mLoadMorePos);
                            }
                        });
                    } else {
                        mMainHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                notifyItemInserted(mLoadMorePos);
                            }
                        });
                    }
                } else if (hasExtraRow && previousState != newNetworkState) {
                    mMainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            notifyDataSetChanged();
                        }
                    });
                }
            }
        }
    }

    @Override
    public int getItemCount() {
        return super.getItemCount() + (hasExtraRow() ? 1 : 0);
    }

    @Override
    public int getItemViewType(int position) {
        int adapterCount = super.getItemCount();
        if (position < adapterCount) {
            return getBaseItemViewType(position);
        } else {
            return LOADING_VIEW_TYPE;
        }
    }

    @Override
    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewHolder baseViewHolder = null;
        switch (viewType) {
            case LOADING_VIEW_TYPE:
                baseViewHolder = new DefaultViewHolder(LayoutInflater.from(parent.getContext())
                        .inflate(mPageLoadMoreView.getLayoutId(), parent, false));
                break;

            default:
                baseViewHolder = onCreateBaseViewHolder(parent, viewType);
                break;
        }

        return (VH) baseViewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int positions) {
        int viewType = holder.getItemViewType();
        switch (viewType) {
            case LOADING_VIEW_TYPE:
                mPageLoadMoreView.convert(holder, mNetworkState);
                holder.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (mNetworkState.getStatus() == NetworkState.Status.FAILED) {
                            if (mRetryCallback != null) {
                                mRetryCallback.onErrorRetry();
                            }
                        }
                    }
                });
                break;

            default:
                onBindBaseViewHolder(holder, getItem(holder.getLayoutPosition()));
                break;
        }
    }

    protected abstract void onBindBaseViewHolder(ViewHolder holder, T item);

    protected abstract ViewHolder onCreateBaseViewHolder(ViewGroup parent, int viewType);

    protected abstract int getBaseItemViewType(int position);

    @Override
    public void onViewAttachedToWindow(ViewHolder holder) {
        super.onViewAttachedToWindow((VH) holder);
        int type = holder.getItemViewType();
        if (type == LOADING_VIEW_TYPE) {
            setFullSpan(holder);
        }
    }

    protected void setFullSpan(ViewHolder holder) {
        if (holder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) {
            StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder.itemView
                    .getLayoutParams();
            params.setFullSpan(true);
        }
    }

    @Override
    public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    int type = getItemViewType(position);
                    if (mSpanSizeLookup == null) {
                        return isFixedViewType(type) ? gridManager.getSpanCount() : 1;
                    } else {
                        return (isFixedViewType(type)) ? gridManager.getSpanCount() : mSpanSizeLookup
                                .getSpanSize(gridManager, position);
                    }
                }

            });
        }
    }

    protected boolean isFixedViewType(int type) {
        return type == LOADING_VIEW_TYPE;
    }

    private SpanSizeLookup mSpanSizeLookup;

    public interface SpanSizeLookup {
        int getSpanSize(GridLayoutManager gridLayoutManager, int position);
    }

    public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) {
        this.mSpanSizeLookup = spanSizeLookup;
    }

    public class DefaultViewHolder extends ViewHolder {
        public DefaultViewHolder(View itemView) {
            super(itemView);
        }
    }

    public interface OnItemClickListener {
        <T> void onItemClick(View view, T t);
    }

    public interface RetryCallback {
        void onErrorRetry();
    }
}
